/* trigonometry.cpp
Michael Zahniser, 12/12/09

Function definitions for the trigonometry class.
*/

#include "Operators.h"

#include <cmath>

using std::string;

namespace {
	string Pi = "pi";
	static const Do<Pi> pi_op;
	
	string Sine = "sine sin";
	static const Do<Sine> sine;
	
	string Cosine = "cosine cos";
	static const Do<Cosine> cosine;
	
	string Tangent = "tangent tan";
	static const Do<Tangent> tangent;
	
	string ArcSine = "arcsine asin";
	static const Do<ArcSine> arcsine;
	
	string ArcCosine = "arccosine acos";
	static const Do<ArcCosine> arccosine;
	
	string ArcTangent = "arctangent atan";
	static const Do<ArcTangent> arctangent;
	
	string Angle = "angle atan2";
	static const Do<Angle> angle;
	
	string ToDegrees = "todegrees todeg";
	static const Do<ToDegrees> todegrees;
	
	string ToRadians = "toradians torad";
	static const Do<ToRadians> toradians;
	
	static const double pi = 3.14159265358979323846;
	
	double PopAngle(State &state)
	{
		double value = state.Pop();
		if(state.Angle() == State::DEGREES)
			value *= pi / 180.;
		return value;
	}
	
	void PushAngle(double value, State &state)
	{
		if(state.Angle() == State::DEGREES)
			value *= 180. / pi;
		state.Push(value);
	}
}



template <> void Do<Pi>::operator()(State &state) const
{
	state.Push(pi);
}



template <> void Do<Sine>::operator()(State &state) const
{
	state.Push(std::sin(PopAngle(state)));
}



template <> void Do<Cosine>::operator()(State &state) const
{
	state.Push(std::cos(PopAngle(state)));
}



template <> void Do<Tangent>::operator()(State &state) const
{
	state.Push(std::tan(PopAngle(state)));
}



template <> void Do<ArcSine>::operator()(State &state) const
{
	PushAngle(std::asin(state.Pop()), state);
}



template <> void Do<ArcCosine>::operator()(State &state) const
{
	PushAngle(std::acos(state.Pop()), state);
}



template <> void Do<ArcTangent>::operator()(State &state) const
{
	PushAngle(std::atan(state.Pop()), state);
}



template <> void Do<Angle>::operator()(State &state) const
{
	double y = state.Pop();
	double x = state.Pop();
	PushAngle(std::atan2(x, y), state);
}



template <> void Do<ToDegrees>::operator()(State &state) const
{
	state.Push(state.Pop() * 180. / pi);
}



template <> void Do<ToRadians>::operator()(State &state) const
{
	state.Push(state.Pop() * pi / 180.);
}
